﻿using SiMay.Sockets.Delegate;
using SiMay.Sockets.Tcp.Awaitable;
using SiMay.Sockets.Tcp.Session;
using SiMay.Sockets.Tcp.TcpConfiguration;
using SiMay.Sockets.UtilityHelper;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SiMay.Sockets.Tcp.Client
{
    /// <summary>
    /// Tcp客户端异步类
    /// </summary>
    public class TcpSocketSaeaClientAgent : TcpSocketSaeaEngineBased
    {
        private bool _isRuning = false;

        /// <summary>
        /// 创建客户端对象
        /// </summary>
        /// <param name="saeaSessionType">接收数据模式</param>
        /// <param name="configuration">配置信息</param>
        /// <param name="completetionNotify">异步回调事件</param>
        internal TcpSocketSaeaClientAgent(
            TcpSocketSaeaSessionType saeaSessionType,
            TcpSocketSaeaClientConfiguration configuration,
            NotifyEventHandler<TcpSocketCompletionNotify,
            TcpSocketSaeaSession> completetionNotify)
            : base(saeaSessionType, configuration, completetionNotify)
        {
            //如果模式是Packet(自动分包)而且开启心跳监测
            if (configuration.AppKeepAlive && saeaSessionType == TcpSocketSaeaSessionType.Packet)
            {
                //在后台执行心跳包检测线程
                var keepAliveThread = new Thread(AppKeepAliveWorkThread);
                keepAliveThread.IsBackground = true;
                keepAliveThread.Start();
            }
        }

        /// <summary>
        /// 心跳包检测线程
        /// </summary>
        private void AppKeepAliveWorkThread()
        {
            byte[] emptyHeart = new byte[] { 0, 0, 0, 0 };

            while (this._isRuning)
            {
                //循环所有已连接的Session，发送4个0的数据包
                for (int i = 0; i < TcpSocketSaeaSessions.Count; i++)
                {
                    var session = (TcpSocketSaeaPackBased)TcpSocketSaeaSessions[i];
                    if (session.State == TcpSocketConnectionState.Closed)
                    {
                        LogHelper.WriteLog("client_heart_thread = Closed");
                        TcpSocketSaeaSessions.RemoveAt(i); i--;
                        continue;
                    }

                    if ((int)(DateTime.Now - session.LastReceiveDataTime).TotalSeconds > 5)
                    {
                        LogHelper.WriteLog("client_heart_thread_timeout ! state：" + session.State.ToString() + " present_time：" + DateTime.Now.ToString() + " heart_time：" + session.LastReceiveDataTime.ToString());
                        if (session.State == TcpSocketConnectionState.Connected)
                        {
                            session.Close(true);
                            TcpSocketSaeaSessions.RemoveAt(i); i--;
                        }
                    }
                    else
                    {
                        //如果数据正在发送，就不发送心跳
                        if (session._intervalIsUseChannel == 0)
                        {
                            var awaiter = HandlerSaeaPool.Take();

                            //4个字节空包头
                            awaiter.Saea.SetBuffer(emptyHeart, 0, emptyHeart.Length);
                            SaeaExHelper.SendAsync(session.Socket, awaiter, (a, e) => HandlerSaeaPool.Return(a));
                        }
                    }
                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <param name="ipEndPoint">服务器IP和端口等信息</param>
        public bool ConnectToServer(IPEndPoint ipEndPoint)
        {
            int _result = 0;
            //创建一个Socket对象
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this._isRuning = true;

            //从异步操作池取出一个对象
            SaeaAwaiter awaiter = HandlerSaeaPool.Take();

            awaiter.Saea.RemoteEndPoint = ipEndPoint;

            //调用异步连接服务器成功方法
            SaeaExHelper.ConnectAsync(socket, awaiter, (a, e) =>
             {
                 //异步操作结束，将异步操作对象初始化并释放回池
                 HandlerSaeaPool.Return(a);

                 var session = SessionPool.Take();

                 if (e != SocketError.Success)
                 {
                     LogHelper.WriteLog("client_connect-error");
                     //如果是连接失败，调用关闭连接的回调方法
                     CompletetionNotify?.Invoke(TcpSocketCompletionNotify.OnConnectedError, session);
                     //将Session释放回池
                     SessionPool.Return(session);
                     _result = 2;
                 }
                 else
                 {
                     _result = 1;
                 }
                 //将连接成功的Session添加到已经连接的List里
                 TcpSocketSaeaSessions.Add(session);
                 //将Socket关联到Session
                 session.Attach(socket);
                 //调用连接成功回调方法
                 CompletetionNotify?.Invoke(TcpSocketCompletionNotify.OnConnected, session);

                 session.StartProcess();
             });

            for (int i = 0; i < 20; i++)
            {
                if (_result > 0)
                {
                    if (_result == 1)
                    {
                        return true;
                    }
                    if (_result == 2)
                    {
                        return false;
                    }
                }
                Thread.Sleep(50);
            }
            return false;
        }

        /// <summary>
        /// 释放客户端
        /// </summary>
        public override void Dispose()
        {
            this._isRuning = false;
            base.Dispose();
        }
    }
}
